package permission

import (
	"context"
	"errors"
	"fmt"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"gorm.io/gorm"
	model2 "k9-panel/app/model"
	"k9-panel/app/service/contract"
	"k9-panel/pkg/gmap"
	"k9-panel/pkg/gslice"
	"strconv"
	"strings"
)

var (
	Perm     *CasbinService
	AclModel = `[request_definition]
				r = sub, obj, act
				
				[policy_definition]
				p = sub, obj, act
				
				[policy_effect]
				e = some(where (p.eft == allow))
				
				[matchers]
				m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
	`
)

type CasbinService struct {
	*casbin.Enforcer
	//adapter  *gormadapter.Adapter
}

func Init(db *gorm.DB) error {
	service, err := NewCasbinService(db)
	if err != nil {
		return err
	}
	Perm = service
	return nil
}

func NewCasbinService(db *gorm.DB) (*CasbinService, error) {
	adapter, err := gormadapter.NewAdapterByDBUseTableName(db, "", "casbin_rule")
	if err != nil {
		return nil, err
	}
	modelCfg, _ := model.NewModelFromString(AclModel)
	enforcer, err := casbin.NewEnforcer(modelCfg, adapter)
	if err != nil {
		return nil, err
	}
	return &CasbinService{
		enforcer,
		//adapter:  adapter,
	}, nil
}

type CommonResource string

func (e CommonResource) Parse() (group string, name string, id int, err error) {
	parts := strings.Split(string(e), ":")
	if len(parts) != 3 {
		return "", "", 0, errors.New("资源格式异常！")
	}
	id, err = strconv.Atoi(parts[2])

	if err != nil {
		return "", "", 0, err
	}
	return parts[0], parts[1], id, err
}
func (e CommonResource) Id() string {
	parts := strings.Split(string(e), ":")
	if len(parts) == 3 {
		return parts[2] // 返回 ID 部分
	}
	return "" // 如果格式不正确，返回空字符串
}

func (e CommonResource) Name() string {
	parts := strings.Split(string(e), ":")
	if len(parts) >= 1 {
		return parts[1] // 返回 Name 部分
	}
	return "" // 如果格式不正确，返回空字符串
}

func (e CommonResource) Group() string {
	parts := strings.Split(string(e), ":")
	if len(parts) > 0 {
		return parts[0] // 返回 Name 部分
	}
	return "" // 如果格式不正确，返回空字符串
}
func ToResource(resource interface{}) (CommonResource, error) {
	if v, ok := resource.(model2.Environment); ok {
		return CommonResource(fmt.Sprintf("env:%s:%d", v.Name, v.ID)), nil
	}
	if v, ok := resource.(model2.Project); ok {
		return CommonResource(fmt.Sprintf("pro:%s:%d", v.Name, v.ID)), nil
	}
	return "", errors.New("类型不支持！")
}
func (receiver CasbinService) IsGrantAll(ids []int) bool {
	return gslice.InSlice(ids, -1)
}
func (receiver CasbinService) GetOwnEnvIDs(ctx context.Context, username string, envSvc contract.IEnvironment) ([]uint, error) {
	var (
		resources map[string]int
	)
	resources = make(map[string]int)
	policies, _ := receiver.GetPermissionsForUser(username)
	//  policy 格式为 [sub, obj, act]

	for _, policy := range policies {
		if len(policy) >= 2 && strings.HasPrefix(policy[1], "env:") {
			envInfo := CommonResource(policy[1])
			_, name, id, err := envInfo.Parse()
			if err != nil {
				return nil, err
			}
			resources[name] = id
		}
	}

	values := gmap.MapValues[string, int](resources)

	if receiver.IsGrantAll(values) {
		list, err := envSvc.List()
		if err != nil {
			return nil, err
		}
		resources = make(map[string]int)
		for _, env := range list {
			resources[env.Name] = int(env.ID)
		}
	}
	values = gmap.MapValues[string, int](resources)
	resourceId := make([]uint, 0)
	for _, resId := range values {
		resourceId = append(resourceId, uint(resId))
	}
	return resourceId, nil

}

func (receiver CasbinService) GetOwnEnv(ctx context.Context, username string) ([]string, error) {
	var (
		resources map[string]int
	)
	resources = make(map[string]int)
	policies, _ := receiver.GetPermissionsForUser(username)
	//  policy 格式为 [sub, obj, act]

	for _, policy := range policies {
		if len(policy) >= 2 && strings.HasPrefix(policy[1], "env:") {
			envInfo := strings.Split(policy[1], ".")
			resources[envInfo[1]] = 1
		}
	}
	return gmap.MapKeys(resources), nil

}

func (receiver CasbinService) GetOwnProject(ctx context.Context, username string) ([]string, error) {
	var (
		resources map[string]interface{}
	)
	resources = make(map[string]interface{})
	policies, _ := receiver.GetPermissionsForUser(username)
	//  policy 格式为 [sub, obj, act]

	for _, policy := range policies {
		if len(policy) >= 2 && strings.HasPrefix(policy[1], "project:") {
			envInfo := strings.Split(policy[1], ".")
			resources[envInfo[1]] = 1
		}
	}
	return gmap.MapKeys(resources), nil

}

func (receiver CasbinService) GetOwnProjectIds(ctx context.Context, username string, project contract.IProject) ([]uint, error) {
	var (
		resources map[string]int
	)
	resources = make(map[string]int)
	policies, _ := receiver.GetPermissionsForUser(username)
	//  policy 格式为 [sub, obj, act]

	for _, policy := range policies {
		if len(policy) >= 2 && strings.HasPrefix(policy[1], "project:") {
			resInfo := CommonResource(policy[1])
			_, name, id, err := resInfo.Parse()
			if err != nil {
				return nil, err
			}
			resources[name] = id
		}
	}
	values := gmap.MapValues[string, int](resources)

	if receiver.IsGrantAll(values) {
		list, err := project.List()
		if err != nil {
			return nil, err
		}
		resources = make(map[string]int)
		for _, env := range list {
			resources[env.Name] = int(env.ID)
		}
	}
	values = gmap.MapValues[string, int](resources)
	resourceId := make([]uint, 0)
	for _, resId := range values {
		resourceId = append(resourceId, uint(resId))
	}
	return resourceId, nil

}
